module ysyx_22040213_axi_interface(
  input clk,
  input rst,
  //----------icache-------------//

  input i_axi_icache_rd_req,
//  input [2:0] i_axi_icache_rd_type,
  input [63:0] i_axi_icache_rd_addr,
  output o_axi_icache_rd_rdy,

  output reg o_axi_icache_ret_valid,
  output reg o_axi_icache_ret_last,
  output [63:0] o_axi_icache_ret_data,

//  input i_axi_icache_wr_req,
//  input [2:0] i_axi_icache_wr_type,
//  input [63:0] i_axi_icache_wr_addr,
//  input [7:0] i_axi_icache_wr_wstrb,
//  input [63:0] i_axi_icache_wr_data,
  output o_axi_icache_wr_rdy,	

  //-----------dcache-----------//
  input i_axi_dcache_rd_req,
//  input [2:0] i_axi_dcache_rd_type,
  input [63:0] i_axi_dcache_rd_addr,
  output o_axi_dcache_rd_rdy,

  output reg o_axi_dcache_ret_valid,
  output reg o_axi_dcache_ret_last,
  output [63:0] o_axi_dcache_ret_data,

  input i_axi_dcache_wr_req,
//  input [2:0] i_axi_dcache_wr_type,
  input [63:0] i_axi_dcache_wr_addr,
  input [7:0] i_axi_dcache_wr_wstrb,
  input [63:0] i_axi_dcache_wr_data,
  output o_axi_dcache_wr_rdy,	

  //----------inst sram like-------------//

  //input i_axi_inst_wr,
  //input [2:0]  i_axi_inst_size,
  //input [7:0]  i_axi_inst_wstrb,

//  input i_axi_inst_req,
//  input [63:0] i_axi_inst_addr,

//  output o_axi_inst_addr_ok,
//  output reg o_axi_inst_data_ok,
//  output [63:0] o_axi_inst_rdata,

  //-----------data sram like-----------//
/*  input i_axi_data_wr,
  input i_axi_data_req,
//  input [2:0]  i_axi_data_size,
  input [63:0] i_axi_data_addr,
  input [7:0]  i_axi_data_wstrb,
  input [63:0] i_axi_data_wdata,

  output o_axi_data_addr_ok,
  output o_axi_data_data_ok,
  output [63:0] o_axi_data_rdata,
  */
  //-----------AXI----------------------//
  //-----------ar-----------------------//
  input i_axi_master_arready,
  output o_axi_master_arvalid,

  output [63:0] o_axi_master_araddr,
  output [3:0]  o_axi_master_arid,
  output [7:0]  o_axi_master_arlen,
  output [2:0]  o_axi_master_arsize,
  output [1:0]  o_axi_master_arburst,
  
  //------------r-----------------------//
  output o_axi_master_rready,

  input i_axi_master_rvalid,
 // input i_axi_master_rlast,
 // input [1:0]  i_axi_master_rresp,
  input [63:0] i_axi_master_rdata,
  input [3:0]  i_axi_master_rid,
  
  //------------aw-----------------------//
  input i_axi_master_awready,

  output reg o_axi_master_awvalid,
  output [63:0] o_axi_master_awaddr,
  output [3:0]  o_axi_master_awid,
  output [7:0]  o_axi_master_awlen,
  output [2:0]  o_axi_master_awsize,
  output [1:0]  o_axi_master_awburst,

  //-------------w-----------------------//
  input i_axi_master_wready,

  output reg o_axi_master_wvalid,
  output [63:0] o_axi_master_wdata,
  output [7:0]  o_axi_master_wstrb,
  output  o_axi_master_wlast,

  //-------------b-----------------------//
  output reg o_axi_master_bready,

  input i_axi_master_bvalid
 // input [1:0] i_axi_master_bresp,
//  input [3:0] i_axi_master_bid

);
/* verilator lint_off UNDRIVEN */
/* verilator lint_off UNUSED */
reg[2:0] size;
//wire need = i_axi_dcache_wr_addr == 64'h830699c8 && i_axi_dcache_wr_req;
always @(*) begin
  case (i_axi_data_wstrb[7:0])
	8'b00001000,
	8'b00000100,
 	8'b00000010,
	8'b00000001: begin 
		size = 3'b000;
	end
	8'b00000011,
	8'b00001100: begin
		size = 3'b001;
	end
	8'b00001111: begin 	
		size = 3'b010;		
	end
	8'hff:begin
		size = 3'b011;
	end
	default: begin
		size = 3'b011;
	end	
  endcase		  
end			

reg [63:0] read_addr;
reg [1:0]  read_burst;
reg [63:0] read_result;
reg [1:0] if_and_mem_read_status; //[1]: 0 inst, 1 data;[0] reading, 1 done
reg read_en;

reg [63:0] write_addr;
reg [1:0] write_burst;
reg [63:0] write_data;
reg [7:0]  write_strb;
reg write_done;
reg write_en;

//----------dcache-sram-line-transfer------------//
wire i_axi_data_wr = i_axi_dcache_wr_req;
wire i_axi_data_req = i_axi_dcache_rd_req  || i_axi_dcache_wr_req;
wire [63:0] i_axi_data_wdata = i_axi_dcache_wr_data;
wire [7:0] i_axi_data_wstrb = i_axi_dcache_wr_wstrb;
reg [63:0] o_axi_data_rdata;
reg o_axi_data_data_ok;
reg o_axi_inst_data_ok;
//assign o_axi_dcache_ret_data = o_axi_data_rdata;
//assign o_axi_dcache_ret_valid = o_axi_data_data_ok;
//assign o_axi_dcache_ret_last = o_axi_data_data_ok;
//assign o_axi_data_addr_ok = i_axi_data_wr? !write_en : !read_en;

wire data_read_req = i_axi_data_req && i_axi_dcache_rd_req;

wire o_axi_inst_addr_ok = !read_en && !data_read_req;

//cache signal
assign o_axi_icache_rd_rdy = o_axi_inst_addr_ok;
assign o_axi_icache_wr_rdy = 1'b1;

assign o_axi_dcache_rd_rdy = !read_en;
assign o_axi_dcache_wr_rdy = !write_en;

//-----------sram like handshake---------//
always @(posedge clk) begin
  if(rst)begin
    read_en <= 1'b0;
    write_en <= 1'b0;
    read_addr <= 64'b0;
    write_addr <= 64'b0;
    o_axi_inst_data_ok <= 1'b0;
    o_axi_data_data_ok <= 1'b0;
    o_axi_icache_ret_valid <= 1'b0;
    o_axi_icache_ret_last <= 1'b0;
    o_axi_dcache_ret_valid <= 1'b0;
    o_axi_dcache_ret_last <= 1'b0;
    read_burst <= 2'b0;
    write_burst <= 2'b0;
    write_strb <= 8'b0;
  end else begin
    if(i_axi_data_req && i_axi_data_wr)begin
      o_axi_data_data_ok <= 1'b0;
    end
    if(!write_en)begin
      if(i_axi_data_req && i_axi_data_wr)begin
        write_addr <= i_axi_dcache_wr_addr;
	write_data <= i_axi_data_wdata;
        write_burst <= 2'b0;
	write_strb <= i_axi_data_wstrb;
        write_en <= 1'b1;
      end else begin
        write_en <= 1'b0;
      end
    end else begin // wire_en
      if(write_done)begin
//        o_axi_data_data_ok <= 1'b1;
	write_en <= 1'b0;
      end else begin
        write_en <= 1'b1;
      end
    end

    if(!read_en)begin
      o_axi_inst_data_ok <= 1'b0;
      o_axi_icache_ret_valid <= 1'b0;
      o_axi_icache_ret_last <= 1'b0;
      o_axi_dcache_ret_valid <= 1'b0;
      o_axi_dcache_ret_last <= 1'b0;
      if(i_axi_data_req && i_axi_dcache_rd_req)begin
        read_addr <= i_axi_dcache_rd_addr;
//	read_burst <= i_axi_data_burst;
	if_and_mem_read_status[1] <= 1'b1; //data read
	read_en <= 1'b1;
	o_axi_data_data_ok <= 1'b0;
        o_axi_icache_ret_valid <= 1'b0;
        o_axi_icache_ret_last <= 1'b0;
      end else if (i_axi_icache_rd_req)begin
        read_addr <= i_axi_icache_rd_addr;
//	read_burst <= i_axi_inst_burst;
	if_and_mem_read_status[1] <= 1'b0;
	read_en <= 1'b1;
//      end else if (i_axi_inst_req)begin
  //      read_addr <= i_axi_inst_addr;
////	read_burst <= i_axi_inst_burst;
//	if_and_mem_read_status[1] <= 1'b0;
//	read_en <= 1'b1;
      end else begin
        read_en <= 1'b0;
      end
    end else begin //read_en
      if(if_and_mem_read_status[1])begin
        //data read
        if(if_and_mem_read_status[0])begin
	  //read done
	  o_axi_data_rdata <= read_result;
	  o_axi_data_data_ok <= 1'b1;
	  o_axi_dcache_ret_valid <= 1'b1;
	  o_axi_dcache_ret_last <= 1'b1;
	  o_axi_dcache_ret_data <= read_result;
	  read_en <= 1'b0;
  	end else begin
  	  //reading
	  read_en <= 1'b1;
	  o_axi_data_data_ok <= 1'b0;
	end
      end else begin
        //inst read
	if(if_and_mem_read_status[0])begin
	  //read done
//	  o_axi_inst_rdata <= read_result;
	  o_axi_inst_data_ok <= 1'b1;
	  o_axi_icache_ret_valid <= 1'b1;
	  o_axi_icache_ret_last <= 1'b1;
	  o_axi_icache_ret_data <= read_result;
	  read_en <= 1'b0;
        end else begin
	  //reading
          read_en <= 1'b1;
	  o_axi_inst_data_ok <= 1'b0;
	  o_axi_icache_ret_valid <= 1'b0;
	  o_axi_icache_ret_last <= 1'b0;

	end
      end
    end
  end
end

//axi write
reg [1:0] write_status;
assign o_axi_master_awaddr = write_addr;
assign o_axi_master_awlen  = 8'b0;
assign o_axi_master_awsize = 3'b010;//4 byte
assign o_axi_master_awburst = 2'b01;//incr
assign o_axi_master_awid = 4'b1; //mem

always @(posedge clk)begin
  if(!write_en)begin
    write_status <= 2'b00;
    write_done <= 1'b0;
    o_axi_master_awvalid <= 1'b0;
    o_axi_master_wvalid <= 1'b0;
    o_axi_master_bready <= 1'b0;
  end else begin
    case(write_status)
      2'b00: begin
        //ready to handshake
        write_status <= 2'b01;
	o_axi_master_awvalid <= 1'b1;
      end
      2'b01: begin
        if(o_axi_master_awvalid && i_axi_master_awready)begin
	  // aw handshake
	  o_axi_master_awvalid <= 1'b0;
	  write_status <= 2'b10;
	  o_axi_master_wvalid <= 1'b1;
        end else begin
	  // not handshake wait still
           o_axi_master_awvalid <= 1'b1;
	  write_status <= 2'b01;
	  o_axi_master_wvalid <= 1'b0;
	end
      end
      2'b10: begin
        if(i_axi_master_wready && o_axi_master_wvalid)begin 
         //w handshake
         write_status <= 2'b11;
	 o_axi_master_wvalid <= 1'b0;
	 o_axi_master_bready <= 1'b1;
        end
      end
      2'b11: begin
        //b handshake
	if(o_axi_master_bready && i_axi_master_bvalid)begin
	  o_axi_master_bready <= 1'b0;
	  write_done <= 1'b1;
	end else begin
	  write_status <= 2'b11;
	end
      end
      default: begin
	write_done <= 1'b0;
	write_status <= 2'b00;
      end
    endcase
  end
end

assign o_axi_master_wdata = o_axi_master_wvalid ? write_data : 64'b0;
assign o_axi_master_wstrb = o_axi_master_wvalid ? write_strb : 8'b0;
assign o_axi_master_wlast = o_axi_master_wvalid ? 1'b1 : 1'b0;

//axi read
reg [1:0] read_status;
assign o_axi_master_araddr = read_addr;
assign o_axi_master_arlen = 8'b0; //no burst 
assign o_axi_master_arsize = !if_and_mem_read_status[1] ? 3'b010 : if_and_mem_read_status[0] ? 3'b010 : size;
assign o_axi_master_arburst = 2'b01;
assign o_axi_master_arid = !if_and_mem_read_status[1] ? 4'b0 : 4'b1;

wire read_diff = i_axi_master_rid != o_axi_master_arid;

always @(posedge clk)begin
  if(!read_en)begin
    read_status <= 2'b00;
    if_and_mem_read_status[0] <= 1'b0;
    o_axi_master_arvalid <= 1'b0;
    o_axi_master_rready <= 1'b0;
  end else begin
    case(read_status)
      2'b00: begin
	 //ready to ar hand shake
        read_status <= 2'b01;
	o_axi_master_arvalid <= 1'b1;
      end
      2'b01: begin
        //ar hand shake
	if(o_axi_master_arvalid && i_axi_master_arready)begin
	  o_axi_master_arvalid <= 1'b0;
	  read_status <= 2'b10;
	  o_axi_master_rready <= 1'b1;
        end else begin
          o_axi_master_arvalid <= 1'b1;
	  read_status <= 2'b01;
	  o_axi_master_rready <= 1'b0;
	end
      end
      2'b10: begin
        //r hand shake
        if(o_axi_master_rready && i_axi_master_rvalid)begin
          read_result <= i_axi_master_rdata;
	  //rlast
	  if_and_mem_read_status[0] <= 1'b1;
	  o_axi_master_rready <= 1'b0;
        end
      end
      default: begin
	if_and_mem_read_status[0] <= 1'b0;
	read_status <= 2'b00;
      end
    endcase
  end
end
endmodule

































